#include <stdio.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sqlite3.h>
#include <string.h>

// 用户登录验证
int login_user(sqlite3 *db, const char *username, const char *password)
{
    char *sql = "SELECT 1 FROM user WHERE username = ? AND password = ?;";
    sqlite3_stmt *stmt;
    if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK)
    {
        fprintf(stderr, "准备SQL语句失败: %s\n", sqlite3_errmsg(db));
        return -1;
    }
    // 绑定参数
    sqlite3_bind_text(stmt, 1, username, -1, SQLITE_STATIC);
    sqlite3_bind_text(stmt, 2, password, -1, SQLITE_STATIC);
    // 执行查询
    int result = (sqlite3_step(stmt) == SQLITE_ROW) ? 0 : -1;

    sqlite3_finalize(stmt);

    if (result == 0)
    {
        printf("登录成功\n");
    }
    else
    {
        printf("用户名或密码错误\n");
    }
    return result;
}

// 用户注册
int register_user(sqlite3 *db, const char *username, const char *password)
{
    // 检查用户名是否已存在
    char *sql_check = "SELECT 1 FROM user WHERE username = ?;";
    sqlite3_stmt *stmt;

    if (sqlite3_prepare_v2(db, sql_check, -1, &stmt, NULL) != SQLITE_OK)
    {
        fprintf(stderr, "准备SQL语句失败: %s\n", sqlite3_errmsg(db));
        return -1;
    }

    sqlite3_bind_text(stmt, 1, username, -1, SQLITE_STATIC);

    if (sqlite3_step(stmt) == SQLITE_ROW)
    {
        sqlite3_finalize(stmt);
        printf("该用户名已存在\n");
        return -1;
    }
    sqlite3_finalize(stmt);

    // 插入新用户
    char *sql_insert = "INSERT INTO user (username, password) VALUES (?, ?);";

    if (sqlite3_prepare_v2(db, sql_insert, -1, &stmt, NULL) != SQLITE_OK)
    {
        fprintf(stderr, "准备SQL语句失败t: %s\n", sqlite3_errmsg(db));
        return -1;
    }

    sqlite3_bind_text(stmt, 1, username, -1, SQLITE_STATIC);
    sqlite3_bind_text(stmt, 2, password, -1, SQLITE_STATIC);

    if (sqlite3_step(stmt) != SQLITE_DONE)
    {
        fprintf(stderr, "Failed to execute statement: %s\n", sqlite3_errmsg(db));
        sqlite3_finalize(stmt);
        return -1;
    }

    sqlite3_finalize(stmt);
    printf("注册成功\n");
    return 0;
}

int main(int argc, char const *argv[])
{
    // 1.创建套接字
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0)
    {
        perror("套接字创建失败");
        return -1;
    }
    printf("套接字创建成功\n");
    printf("sockfd = %d\n", sockfd);

    // 设置io复用
    int opt = 1;
    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0)
    {
        perror("设置套接字选项失败");
        return -1;
    }
    printf("设置套接字选项成功\n");

    // 2.绑定网络信息
    struct sockaddr_in server_addr, client_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(8886);
    server_addr.sin_addr.s_addr = INADDR_ANY;
    socklen_t len = sizeof(struct sockaddr_in);

    if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
    {
        perror("套接字绑定失败");
        return -1;
    }
    printf("套接字绑定成功\n");
    // 3.监听客户端连接
    if (listen(sockfd, 5) < 0)
    {
        perror("监听客户端连接失败");
        return -1;
    }
    printf("开始监听客户端连接\n");

    // 打开数据库
    sqlite3 *db;
    if (sqlite3_open("database.db", &db) != SQLITE_OK)
    {
        fprintf(stderr, "无法打开数据库: %s\n", sqlite3_errmsg(db));
        return -1;
    }
    printf("数据库打开成功\n");

    // select并发服务器
    // 构造表
    fd_set rfds;
    fd_set tempfds;
    // 2.清空表 FD_ZERO
    FD_ZERO(&rfds);
    FD_ZERO(&tempfds);
    // 3.将关心的文件描述符添加到表中 FD_SET
    FD_SET(sockfd, &rfds); // sockfd
    int max = sockfd;
    int acceptfd;
    int ret;
    char buf[32] = {0};
    while (1)
    {
        tempfds = rfds;
        // 4.调用select函数，监听 select
        select(max + 1, &tempfds, NULL, NULL, NULL);

        if (FD_ISSET(sockfd, &tempfds))
        {
            // 5.阻塞等待接收客户端连接请求（accept()）-------------》接电话
            acceptfd = accept(sockfd, (struct sockaddr *)&client_addr, &len);
            // accept会返回一个用于通信的文件描述符
            // 在tcp服务器中,有两类套接字,一类是socket函数返回(1个),用于链接的文件描述符
            // 一类是accept函数返回的(1个或者多个),用于通信的文件描述符
            if (acceptfd < 0)
            {
                perror("acceptfd err");
                return -1;
            }
            printf("acceptfd:%d\n", acceptfd);
            printf("ip:%s    port: %d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));

            FD_SET(acceptfd, &rfds);
            if (acceptfd > max)
            {
                max = acceptfd;
            }
        }

        for (int i = sockfd + 1; i <= max; i++)
        {
            if (FD_ISSET(i, &tempfds))
            {
                ret = recv(i, buf, sizeof(buf), 0);
                if (ret < 0)
                {
                    perror("recv err");
                    return -1;
                }
                else if (ret == 0)
                {
                    printf("QT客户端关闭\n");
                    close(i);
                    FD_CLR(i, &rfds); // 从原表中删除
                    // 调整max的值
                    while (!FD_ISSET(max, &rfds))
                        max--;
                }
                else
                {
                    printf("接收到的数据：%s\n", buf);
                    // 处理接收到的数据
                    char *request = strtok(buf, ",");
                    char *username = strtok(NULL, ",");
                    char *password = strtok(NULL, ",");
                    printf("请求类型: %s\n", request);
                    printf("用户名: %s\n", username);
                    printf("密码: %s\n", password);

                    if (strcmp(request, "login") == 0)
                    {
                        // 调用登录验证函数
                        if (login_user(db, username, password) == 0)
                        {
                            // 发送登录成功消息
                            send(i, "登录成功", strlen("登录成功"), 0);
                        }
                        else
                        {
                            // 发送登录失败消息
                            send(i, "用户名或密码错误", strlen("用户名或密码错误"), 0);
                        }
                    }
                    else if (strcmp(request, "register") == 0)
                    {
                        // 调用注册函数
                        if (register_user(db, username, password) == 0)
                        {
                            // 发送注册成功消息
                            send(i, "注册成功", strlen("注册成功"), 0);
                        }
                        else
                        {
                            // 发送注册失败消息
                            send(i, "该用户名已存在", strlen("该用户名已存在"), 0);
                        }
                    }
                }
            }
        }
        memset(buf, 0, sizeof(buf));
    }
    // 关闭数据库
    sqlite3_close(db);
    // 关闭套接字
    close(sockfd);
    return 0;

    return 0;
}
